package com.seo.service.task.impl;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.seo.mapper.bill.proxy.ProxyTransactionMapper;
import com.seo.mapper.proxy.ProxyAccountMapper;
import com.seo.mapper.proxy.ProxyUserMapper;
import com.seo.mapper.proxy.keywords.ProxyKeywordsDetailMapper;
import com.seo.mapper.task.UserKeywordsTaskMapper;
import com.seo.mapper.transaction.TransactionMapperM;
import com.seo.mapper.user.UserMapper;
import com.seo.mapper.user.account.AccountMapper;
import com.seo.mapper.user.keywords.KeywordsDetailMapper;
import com.seo.mapper.user.keywords.NewKeywordsDetailMapper;
import com.seo.pojo.ReturnBody;
import com.seo.utils.CommonUtil;
import com.seo.utils.CustomUtil;
import com.seo.utils.DataUtil;
import com.seo.utils.DateUtil;
import com.seo.utils.SpringUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service(value = "userKeywordsTaskService")
public class UserKeywordsTaskServiceImpl {

	@Autowired
	private UserKeywordsTaskMapper userKeywordsTaskMapper;

	@Autowired
	private KeywordsDetailMapper keywordsDetailMapper;

	@Autowired
	private NewKeywordsDetailMapper newKeywordsDetailMapper;

	@Autowired
	private TransactionMapperM transactionMapperM;

	@Autowired
	private AccountMapper accountMapper;

	@Autowired
	private UserMapper userMapper;

	@Autowired
	private ProxyKeywordsDetailMapper proxyKeywordsDetailMapper;

	@Autowired
	private ProxyTransactionMapper proxyTransactionMapper;

	@Autowired
	private ProxyAccountMapper proxyAccountMapper;

	@Autowired
	private ProxyUserMapper proxyUserMapper;

	@Autowired
	private UserKeywordsToolServiceImpl userKeywordsToolService;

	public void runUserKeywordsDeduc() {
		String tradeId = CommonUtil.getUUID();
		String time = DateUtil.getAfterDayDate(DateUtil.getTimesmorning(), -1, 1);
		String curTime = DateUtil.getTime();
		ReturnBody rb = ReturnBody.init();
		log.info("[{}]-【定时任务-用户关键词扣费开始,任务时间[{}],执行时间[{}]】", tradeId, time, curTime);

		UserKeywordsTaskServiceImpl userKeywordsTaskService = (UserKeywordsTaskServiceImpl) SpringUtil
				.getBean("userKeywordsTaskService");

		rb.run(userKeywordsTaskService.saveUserKeywordsTask(tradeId, time, curTime));
		if (!rb.isSuccess()) {
			return;
		}

		log.info("[{}]-优化扣费,任务时间[{}],执行时间[{}]-开始", tradeId, time, curTime);
		long min = 0;
		int num = 1000;

		rb.run(userKeywordsTaskService.getUserKeywordsDeduc(tradeId, time, min, num));

		if (!rb.isSuccess()) {
			return;
		}

		log.info("优化扣费-结束");

		log.info("[{}]-新站扣费,任务时间[{}],执行时间[{}]-开始", tradeId, time, curTime);
		min = 0;
		num = 1000;

		rb.run(userKeywordsTaskService.getNewUserKeywordsDeduc(tradeId, time, min, num));

		if (!rb.isSuccess()) {
			return;
		}

		log.info("新站扣费-结束");

	}

	public ReturnBody runUserKeywordsDeduc(String tradeId, String time, boolean isAgain) {
		ReturnBody rb = ReturnBody.init();

		if (StringUtils.isEmpty(time)) {
			log.error("[{}]-定时任务-调度时间不能为空", time);
			return rb.error();
		}

		String curTime = DateUtil.getTime();

		log.info("[{}]-【定时任务-用户关键词扣费开始,任务时间[{}],执行时间[{}]】", tradeId, time, curTime);

		UserKeywordsTaskServiceImpl userKeywordsTaskService = (UserKeywordsTaskServiceImpl) SpringUtil
				.getBean("userKeywordsTaskService");

		if (isAgain) {
			rb.run(userKeywordsTaskService.saveUserKeywordsTask(tradeId, time, curTime));
			if (!rb.isSuccess()) {
				return rb;
			}
		} else {
			rb.run(getUserKeywordsTask(tradeId, time));
			if (!rb.containsKey("task")) {
				log.error("[{}]-【定时任务-用户关键词扣费-调度不存在】", tradeId);
				return rb.rollback();
			}
		}

		log.info("[{}]-优化扣费,任务时间[{}],执行时间[{}]-开始", tradeId, time, curTime);
		long min = 0;
		int num = 1000;

		rb.run(userKeywordsTaskService.getUserKeywordsDeduc(tradeId, time, min, num));

		if (!rb.isSuccess()) {
			return rb;
		}
		log.info("优化扣费-结束");

		log.info("[{}]-新站扣费,任务时间[{}],执行时间[{}]-开始", tradeId, time, curTime);
		min = 0;
		num = 1000;

		rb.run(userKeywordsTaskService.getNewUserKeywordsDeduc(tradeId, time, min, num));

		if (!rb.isSuccess()) {
			return rb;
		}

		log.info("新站扣费-结束");
		return rb.success();
	}

	public ReturnBody saveUserKeywordsTask(String tradeId, String time, String curTime) {
		ReturnBody rb = ReturnBody.init();
		try {

			rb.run(getUserKeywordsTask(tradeId, time));
			if (rb.containsKey("task")) {
				log.error("[{}]-【定时任务-用户关键词扣费-调度已存在】", tradeId);
				return rb.rollback();
			}

			Map<String, Object> params = new HashMap<>();
			params.put("taskName", "用户关键字扣费");
			params.put("taskCode", "keywords_deduc_task");
			params.put("taskTime", time);
			params.put("runTime", curTime);
			int num = userKeywordsTaskMapper.saveTask(params);
			if (num == 0) {
				log.error("[{}]-【定时任务-用户关键词扣费-调度失败】", tradeId);
				return rb.rollback();
			}

			return rb.success();
		} catch (Exception e) {
			log.error("[{}]-【定时任务-用户关键词扣费-调度異常[{}]】", tradeId, e);
			return rb.rollback();
		} finally {
			rb.result();
		}
	}

	public ReturnBody getUserKeywordsTask(String tradeId, String time) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("taskName", "用户关键字扣费");
		params.put("taskCode", "keywords_deduc_task");
		params.put("taskTime", time);
		List<Map<String, Object>> taskList = userKeywordsTaskMapper.getTask(params);
		if (taskList != null && !taskList.isEmpty()) {
			rb.put("task", taskList.get(0));
		}
		return rb.success();
	}

	public ReturnBody getUserKeywordsDeduc(String tradeId, String time, long min, int num) {
		ReturnBody rb = ReturnBody.init();
		try {
			log.info("[{}]-查询关键字更新明细，日期[{}]", tradeId, time);
			Map<String, Object> params = new HashMap<>();
			params.put("isTarget", "01");
			params.put("runTime", time);
			params.put("min", min);
			params.put("num", num);

			List<Map<String, Object>> kdl = keywordsDetailMapper.getKeywordsDetailList(params);

			if (kdl == null || kdl.isEmpty()) {
				log.info("[{}]-没有关键字更新", tradeId);
				return rb.success();
			}
			log.info("[{}]-关键字扣费", tradeId);
			UserKeywordsTaskServiceImpl userKeywordsTaskService = (UserKeywordsTaskServiceImpl) SpringUtil
					.getBean("userKeywordsTaskService");
			userKeywordsToolService.async(userKeywordsTaskService::saveUserKeywordsDeduc, tradeId, kdl);

			if (kdl.size() < num) {
				log.info("[{}]-关键字扣费结束", tradeId);
				return rb.success();
			}
			min = (Long) kdl.get(kdl.size() - 1).get("id");
			return getUserKeywordsDeduc(tradeId, time, min, num);
		} catch (Exception e) {
			log.error("[{}]-【关键词扣费异常[{}]】", tradeId, e);
			return rb.error("优化扣费异常");
		}
	}

	public ReturnBody getNewUserKeywordsDeduc(String tradeId, String time, long min, int num) {
		ReturnBody rb = ReturnBody.init();
		try {
			log.info("[{}]-查询新站关键字更新明细，日期[{}]", tradeId, time);
			Map<String, Object> params = new HashMap<>();
			params.put("isTarget", "01");
			params.put("runTime", time);
			params.put("min", min);
			params.put("num", num);

			List<Map<String, Object>> kdl = newKeywordsDetailMapper.getNewKeywordsDetailList(params);

			if (kdl == null || kdl.isEmpty()) {
				log.info("[{}]-没有关键字更新", tradeId);
				return rb.success();
			}
			log.info("[{}]-关键字扣费", tradeId);
			UserKeywordsTaskServiceImpl userKeywordsTaskService = (UserKeywordsTaskServiceImpl) SpringUtil
					.getBean("userKeywordsTaskService");
			userKeywordsToolService.async(userKeywordsTaskService::saveNewUserKeywordsDeduc, tradeId, kdl);

			if (kdl.size() < num) {
				log.info("[{}]-新站关键字扣费结束", tradeId);
				return rb.success();
			}
			min = (Long) kdl.get(kdl.size() - 1).get("id");
			return getUserKeywordsDeduc(tradeId, time, min, num);
		} catch (Exception e) {
			log.error("[{}]-【关键词扣费异常[{}]】", tradeId, e);
			return rb.error("新站扣费异常");
		}
	}

	public ReturnBody saveUserKeywordsDeduc(String tradeId, List<Map<String, Object>> kdl) {
		ReturnBody rb = ReturnBody.init();
		try {
			Map<String, Object> minKd = kdl.get(0);
			Map<String, Object> maxKd = kdl.get(kdl.size() - 1);
			log.info("[{}]-关键字扣费,最小id[{}],最大id[{}]", tradeId, minKd, maxKd);

			for (Map<String, Object> kd : kdl) {
				long keywordsId = (long) kd.get("keywordsId");
				long detailId = (long) kd.get("id");

				Map<String, Object> keywords = keywordsDetailMapper.getKeywordsById(keywordsId);
				if (keywords == null || "1".equals(keywords.get("isDelete"))) {
					log.info("[{}]-关键词已删除[{}]", tradeId, keywordsId);
					continue;
				}

				List<Map<String, Object>> kurList = keywordsDetailMapper.getKeywordsUserRelation(keywordsId);
				if (kurList == null || kurList.isEmpty()) {
					log.error("keywordsUserRelation记录不存在[{}]", keywordsId);
					return rb.rollback();
				}
				Map<Long, Map<String, Object>> kddMap = keywordsDetailMapper.getKeywordsddByKddRelation(detailId,null);
				if(kddMap == null || kddMap.isEmpty()) {
					int num = keywordsDetailMapper.updateConsumeDays(keywordsId);
					if (num == 0) {
						log.error("[{}]-更新消费天数-失败", tradeId);
						return rb.rollback();
					}
				}

				for (Map<String, Object> kur : kurList) {
					log.info("[{}]-查看关键词是否已扣费[{}]", tradeId, kd);
					Map<String, Object> kdd = (kddMap != null) ? kddMap.get((long) kur.get("id")):null;
					
					if (kdd != null) {
						log.info("[{}]-关键词已扣费[{}]", tradeId, kdd);
						continue;
					}
					int userId = (int) kur.get("userId");
					Map<String, Object> user = userMapper.getUserById(userId);
					if (user == null) {
						log.error("[{}]-用户不存在-[{}]", tradeId, userId);
						continue;
					}
					kd.put("parentUserId", user.get("parentId"));
					log.info("[{}]-插入账单", tradeId, userId);
					kd.put("userId", userId);
					kd.put("price", kur.get("price"));
					kd.put("keywordsRelationId", kur.get("id"));
					rb.run(saveTransactionFlow(tradeId, kd, "关键词扣费"));
					if (!rb.isSuccess()) {
						return rb;
					}

					log.info("[{}]-更新用户余额,插入余额明细", tradeId);
					rb.run(saveBalanceDetail(tradeId, rb.get("tf", String.class, Object.class)));
					if (!rb.isSuccess()) {
						return rb;
					}
					log.info("[{}]-插入关键词扣费明细", tradeId);
					rb.run(saveKeywordsdd(tradeId, kd, rb.get("bd", String.class, Object.class)));
					if (!rb.isSuccess()) {
						return rb;
					}
				}

				log.info("[{}]-【判断代理客户关键词是否扣费】", tradeId);
				BigDecimal price1 = DataUtil.getBigDecimal(kd.get("price1"));
				if (price1.compareTo(BigDecimal.ZERO) == 1) {
					log.info("[{}]-查看代理客户关键词是否已扣费", tradeId);
					Map<String, Object> pkdd = proxyKeywordsDetailMapper.getProxyKeywordsddByKddId((long) kd.get("id"));
					if (pkdd != null) {
						log.info("[{}]-代理客户关键词已扣费[{}]", tradeId, pkdd);
						continue;
					}
					Integer proxyUserId = (kd.get("proxyUserId") == null) ? null : (Integer) kd.get("proxyUserId");
					log.info("[{}]-查询代理客户是否存在-[{}]", tradeId, proxyUserId);
					if (proxyUserId == null) {
						log.info("[{}]-代理客户Id为空", tradeId);
						continue;
					}
					Map<String, Object> proxyUser = proxyUserMapper.getProxyUserById(proxyUserId);
					if (proxyUser == null) {
						log.info("[{}]-代理客户为空-[{}]", tradeId, proxyUserId);
						continue;
					}

					log.info("[{}]-插入代理账单", tradeId);
					rb.run(saveProxyTransactionFlow(tradeId, kd, "关键词扣费"));
					if (!rb.isSuccess()) {
						return rb;
					}
					log.info("[{}]-更新代理用户余额,插入余额明细", tradeId);
					rb.run(saveProxyBalanceDetail(tradeId, rb.get("proxyTf", String.class, Object.class)));
					if (!rb.isSuccess()) {
						return rb;
					}
					log.info("[{}]-插入代理关键词扣费明细", tradeId);
					rb.run(saveProxyKeywordsdd(tradeId, kd, rb.get("proxyBd", String.class, Object.class)));
					if (!rb.isSuccess()) {
						return rb;
					}
				}
			}

			return rb.success();
		} catch (Exception e) {
			log.error("[{}]-【关键词扣费异常[{}]】", tradeId, e);
			return rb.rollback();
		} finally {
			rb.result();
		}
	}

	public ReturnBody saveNewUserKeywordsDeduc(String tradeId, List<Map<String, Object>> kdl) {
		ReturnBody rb = ReturnBody.init();
		try {
			Map<String, Object> minKd = kdl.get(0);
			Map<String, Object> maxKd = kdl.get(kdl.size() - 1);
			log.info("[{}]-新站关键字扣费,最小id[{}],最大id[{}]", tradeId, minKd, maxKd);

			for (Map<String, Object> kd : kdl) {
				long keywordsId = (long) kd.get("keywordsId");
				long detailId = (long) kd.get("id");
				List<Map<String, Object>> kurList = newKeywordsDetailMapper.getNewKeywordsUserRelation(keywordsId);
				if (kurList == null || kurList.isEmpty()) {
					log.error("keywordsUserRelation记录不存在[{}]", keywordsId);
					return rb.rollback();
				}
				int num = keywordsDetailMapper.updateConsumeDays(keywordsId);
				if (num == 0) {
					log.error("[{}]-更新消费天数-失败", tradeId);
					return rb.rollback();
				}

				for (Map<String, Object> kur : kurList) {
					log.info("[{}]-查看关键词是否已扣费[{}]", tradeId, kd);
					Map<String, Object> kdd = newKeywordsDetailMapper.getNewKeywordsddByKddRelation(detailId,
							(long) kur.get("id"));
					if (kdd != null) {
						log.info("[{}]-关键词已扣费[{}]", tradeId, kdd);
						continue;
					}
					Integer userId = (Integer) kur.get("userId");
					log.info("[{}]-插入账单", tradeId, userId);
					kd.put("userId", userId);
					kd.put("price", kur.get("price"));
					kd.put("keywordsRelationId", kur.get("id"));
					rb.run(saveTransactionFlow(tradeId, kd, "新站关键词扣费"));
					if (!rb.isSuccess()) {
						return rb;
					}

					log.info("[{}]-更新用户余额,插入余额明细", tradeId);
					rb.run(saveBalanceDetail(tradeId, rb.get("tf", String.class, Object.class)));
					if (!rb.isSuccess()) {
						return rb;
					}
					log.info("[{}]-插入关键词扣费明细", tradeId);
					rb.run(saveNewKeywordsdd(tradeId, kd, rb.get("bd", String.class, Object.class)));
					if (!rb.isSuccess()) {
						return rb;
					}
				}

			}

			return rb.success();
		} catch (Exception e) {
			log.error("[{}]-【关键词扣费异常[{}]】", tradeId, e);
			return rb.rollback();
		} finally {
			rb.result();
		}
	}

	public ReturnBody saveTransactionFlow(String tradeId, Map<String, Object> kd, String remark) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("userId", kd.get("userId"));
		params.put("parentUserId", kd.get("parentUserId"));
		params.put("amount", kd.get("price"));
		params.put("payAmount", kd.get("price"));
		params.put("amountState", "02");
		params.put("remark", remark);
		params.put("state", "01");
		params.put("type", "deduc");
		int num = transactionMapperM.saveTransactionFlow(params);
		if (num == 0) {
			log.error("[{}]-插入账单-失败", tradeId);
		}
		params.put("code", CustomUtil.orderCode(3, (long) params.get("id"), (int) params.get("userId")));
		num = transactionMapperM.updateTransactionFlowCode(params);
		if (num == 0) {
			log.error("[{}]-插入账单-失败", tradeId);
		}
		log.info("[{}]-插入账单[{}]-成功", tradeId, params);
		rb.put("tf", params);
		return rb.success();

	}

	public ReturnBody saveProxyTransactionFlow(String tradeId, Map<String, Object> kd, String remark) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("userId", kd.get("realUserId"));
		params.put("proxyUserId", kd.get("proxyUserId"));
		params.put("amount", kd.get("price1"));
		params.put("amountState", "02");
		params.put("remark", remark);
		params.put("state", "01");
		params.put("type", "deduc");
		int num = proxyTransactionMapper.saveProxyTransactionFlow(params);
		if (num == 0) {
			log.error("[{}]-插入代理客户账单-失败", tradeId);
		}
		params.put("code", CustomUtil.orderCode(3, (long) params.get("id"), (int) params.get("proxyUserId")));
		num = proxyTransactionMapper.updateProxyTransactionFlowCode(params);
		if (num == 0) {
			log.error("[{}]-插入代理客户账单-失败", tradeId);
		}
		log.info("[{}]-插入代理客户账单[{}]-成功", tradeId, params);
		rb.put("proxyTf", params);
		return rb.success();

	}

	public ReturnBody saveBalanceDetail(String tradeId, Map<String, Object> tf) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("userId", tf.get("userId"));
		params.put("balance", tf.get("amount"));
		params.put("type", "2");
		int num = accountMapper.updateUserBalance(params);
		if (num == 0) {
			log.error("[{}]-更新用户余额-失败", tradeId);
		}
		params.put("parentUserId", tf.get("parentUserId"));
		params.put("incomeState", "02");
		params.put("type", "deduc");
		params.put("remark", tf.get("remark"));
		params.put("transactionId", tf.get("id"));
		params.put("state", "01");
		num = accountMapper.saveBalanceDetail(params);
		if (num == 0) {
			log.error("[{}]-保存用户余额明细-失败", tradeId);
		}
		rb.put("bd", params);
		return rb.success();
	}

	public ReturnBody saveProxyBalanceDetail(String tradeId, Map<String, Object> proxyTf) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("proxyUserId", proxyTf.get("proxyUserId"));
		params.put("balance", proxyTf.get("amount"));
		params.put("type", "2");
		int num = proxyAccountMapper.updateProxyUserBalance(params);
		if (num == 0) {
			log.error("[{}]-更新代理用户余额-失败", tradeId);
		}
		params.put("userId", proxyTf.get("userId"));
		params.put("incomeState", "02");
		params.put("type", "deduc");
		params.put("remark", proxyTf.get("remark"));
		params.put("transactionId", proxyTf.get("id"));
		params.put("state", "01");
		num = proxyAccountMapper.saveProxyBalanceDetail(params);
		if (num == 0) {
			log.error("[{}]-保存代理用户余额明细-失败", tradeId);
		}
		rb.put("proxyBd", params);
		return rb.success();
	}

	public ReturnBody saveKeywordsdd(String tradeId, Map<String, Object> kd, Map<String, Object> bd) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("keywordsDetailId", kd.get("id"));
		params.put("keywordsRelationId", kd.get("keywordsRelationId"));
		params.put("domain", kd.get("domain"));
		params.put("name", kd.get("name"));
		params.put("engineCode", kd.get("engineCode"));
		params.put("newRanking", kd.get("newRanking"));
		params.put("userId", bd.get("userId"));
		params.put("balanceId", bd.get("id"));
		params.put("amount", kd.get("price"));
		params.put("remark", "关键词扣费");
		params.put("state", "01");
		int num = keywordsDetailMapper.saveKeywordsddByKdd(params);
		if (num == 0) {
			log.error("[{}]-保存用户关键词扣费明细-失败", tradeId);
		}
		
		return rb.success();
	}

	public ReturnBody saveProxyKeywordsdd(String tradeId, Map<String, Object> kd, Map<String, Object> proxyBd) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("keywordsDetailId", kd.get("id"));
		params.put("domain", kd.get("domain"));
		params.put("name", kd.get("name"));
		params.put("engineCode", kd.get("engineCode"));
		params.put("newRanking", kd.get("newRanking"));
		params.put("userId", kd.get("realUserId"));
		params.put("proxyUserId", kd.get("proxyUserId"));
		params.put("balanceId", proxyBd.get("id"));
		params.put("amount", kd.get("price1"));
		params.put("remark", "关键词扣费");
		params.put("state", "01");
		int num = proxyKeywordsDetailMapper.saveProxyKeywordsddByKdd(params);
		if (num == 0) {
			log.error("[{}]-保存代理用户关键词扣费明细-失败", tradeId);
		}
		return rb.success();
	}

	public ReturnBody saveNewKeywordsdd(String tradeId, Map<String, Object> kd, Map<String, Object> bd) {
		ReturnBody rb = ReturnBody.init();
		Map<String, Object> params = new HashMap<>();
		params.put("keywordsDetailId", kd.get("id"));
		params.put("keywordsRelationId", kd.get("keywordsRelationId"));
		params.put("domain", kd.get("domain"));
		params.put("name", kd.get("name"));
		params.put("engineCode", kd.get("engineCode"));
		params.put("newRanking", kd.get("newRanking"));
		params.put("userId", bd.get("userId"));
		params.put("balanceId", bd.get("id"));
		params.put("amount", kd.get("price"));
		params.put("remark", "关键词扣费");
		params.put("state", "01");
		int num = newKeywordsDetailMapper.saveNewKeywordsddByKdd(params);
		if (num == 0) {
			log.error("[{}]-保存用户关键词扣费明细-失败", tradeId);
		}
		return rb.success();
	}

	public List<Map<String, Object>> getTask(Map<String, Object> params) {

		return userKeywordsTaskMapper.getTask(params);
	}
}
